﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Web;
using System.Text.RegularExpressions;

using DesertedRoadStudios.BlogNetNuke.Components;

namespace DesertedRoadStudios.BlogNetNuke.Common
{
    public static class Methods
    {
        public static XDocument GetParams(HttpContext context, int portalID, int moduleID, int tabID)
        {
            string _postPath = string.Empty;
            Guid _postID = Guid.Empty;

            XDocument doc = new XDocument();
            XElement xRoot = new XElement("params");
            doc.Add(xRoot);

            XElement xElement = new XElement("RequestType", RequestType.FullView.ToString());
            xRoot.Add(xElement);

            BlogNetNukeController bnn = new BlogNetNukeController();
            Dictionary<string, string> settings = bnn.GetSettings(portalID, moduleID);

            try
            {
                if (!string.IsNullOrEmpty(context.Request.QueryString["postID"]))
                {
                    doc.Element("params").Element("RequestType").SetValue(RequestType.PostView.ToString());

                    _postID = new Guid(context.Request.QueryString["postID"]);

                    xElement = new XElement("PostID", _postID);
                    xRoot.Add(xElement);
                }
                else if ((!string.IsNullOrEmpty(context.Request.QueryString["Parsed"])) && (Convert.ToInt32(context.Request.QueryString["Parsed"]) == 1))
                {
                    // SEO'ed path
                    if (!string.IsNullOrEmpty(context.Request.QueryString["Sitemap"]) && (context.Request.QueryString["Sitemap"].Equals("1")))
                    {
                        Sitemap.ShowSitemap(Convert.ToInt32(context.Request.QueryString["TabId"]), context.Response);
                    }
                    else
                    {
                        xElement = new XElement("TabID", context.Request.QueryString["TabId"]);
                        xRoot.Add(xElement);

                        if (!string.IsNullOrEmpty(context.Request.QueryString["Category"]))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.CategoryView.ToString());

                            xElement = new XElement("Category", context.Request.QueryString["Category"]);
                            xRoot.Add(xElement);
                        }
                        else if (!string.IsNullOrEmpty(context.Request.QueryString["Tag"]))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.TagView.ToString());

                            xElement = new XElement("Tag", context.Request.QueryString["Tag"]);
                            xRoot.Add(xElement);
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(context.Request.QueryString["Year"]))
                            {
                                doc.Element("params").Element("RequestType").SetValue(RequestType.YearView.ToString());

                                xElement = new XElement("Year", context.Request.QueryString["Year"]);
                                xRoot.Add(xElement);
                            }

                            if (!string.IsNullOrEmpty(context.Request.QueryString["Month"]))
                            {
                                doc.Element("params").Element("RequestType").SetValue(RequestType.MonthView.ToString());

                                xElement = new XElement("Month", context.Request.QueryString["Month"]);
                                xRoot.Add(xElement);
                            }

                            if (!string.IsNullOrEmpty(context.Request.QueryString["Day"]))
                            {
                                doc.Element("params").Element("RequestType").SetValue(RequestType.DayView.ToString());

                                xElement = new XElement("Day", context.Request.QueryString["Day"]);
                                xRoot.Add(xElement);
                            }

                            if (!string.IsNullOrEmpty(context.Request.QueryString["Slug"]))
                            {
                                doc.Element("params").Element("RequestType").SetValue(RequestType.PostView.ToString());

                                xElement = new XElement("Slug", context.Request.QueryString["Slug"]);
                                xRoot.Add(xElement);

                                _postPath = "/" + context.Request.QueryString["Year"] + "/" + context.Request.QueryString["Month"] + "/" + context.Request.QueryString["Day"] + "/" + context.Request.QueryString["Slug"];

                                xElement = new XElement("PostPath", _postPath);
                                xRoot.Add(xElement);
                            }
                        }
                    }
                }
                else
                {
                    //Regex sitemapREX = new Regex("(.+)/sitemap\\.aspx", RegexOptions.IgnoreCase);
                    //Regex tabidREX = new Regex("^(.+)tabid/(\\d+)/(.+)?", RegexOptions.IgnoreCase);
                    //Regex categoryREX = new Regex("(.+)/Category/(.+)\\.aspx", RegexOptions.IgnoreCase);
                    //Regex tagREX = new Regex("(.+)/Tag/(.+)\\.aspx", RegexOptions.IgnoreCase);
                    //Regex slugREX = new Regex("(.+)/(\\d+)/(\\d+)/(\\d+)/(.+)\\.aspx", RegexOptions.IgnoreCase);
                    //Regex dayREX = new Regex("(.+)/(\\d+)/(\\d+)/(\\d+)\\.aspx", RegexOptions.IgnoreCase);
                    //Regex monthREX = new Regex("(.+)/(\\d+)/(\\d+)\\.aspx", RegexOptions.IgnoreCase);
                    //Regex yearREX = new Regex("(.+)/(\\d+)\\.aspx", RegexOptions.IgnoreCase);

                    ParseData data;

                    Regex sitemapREX = new Regex("(.+)/sitemap(.+)", RegexOptions.IgnoreCase);
                    Regex tabidREX = new Regex("^(.+)tabid/(\\d+)/(.+)?", RegexOptions.IgnoreCase);
                    Regex categoryREX = new Regex("(.+)/Category/(.+)", RegexOptions.IgnoreCase);
                    Regex tagREX = new Regex("(.+)/Tag/(.+)", RegexOptions.IgnoreCase);
                    Regex slugREX = new Regex("(.+)/(\\d+)/(\\d+)/(\\d+)/(.+)", RegexOptions.IgnoreCase);
                    Regex dayREX = new Regex("(.+)/(\\d+)/(\\d+)/(\\d+)(.*)", RegexOptions.IgnoreCase);
                    Regex monthREX = new Regex("(.+)/(\\d+)/(\\d+)(.*)", RegexOptions.IgnoreCase);
                    Regex yearREX = new Regex("(.+)/(\\d+)(.*)", RegexOptions.IgnoreCase);

                    string initRequest = context.Request.RawUrl;
                    string newRequest = string.Empty;

                    if (sitemapREX.IsMatch(initRequest))
                    {
                        Sitemap.ShowSitemap(Convert.ToInt32(context.Request.QueryString["TabId"]), context.Response);
                    }
                    else if (tabidREX.IsMatch(initRequest))
                    {
                        xElement = new XElement("TabID", context.Request.QueryString["TabId"]);
                        xRoot.Add(xElement);

                        newRequest = tabidREX.Replace(initRequest, "$1$3");

                        if (categoryREX.IsMatch(newRequest))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.CategoryView.ToString());

                            data = Parse(categoryREX.Replace(newRequest, "$2"), true, settings);
                            xElement = new XElement("Category", data.path);
                            xRoot.Add(xElement);
                        }
                        else if (tagREX.IsMatch(newRequest))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.TagView.ToString());

                            data = Parse(tagREX.Replace(newRequest, "$2"), true, settings);
                            xElement = new XElement("Tag", data.path);
                            xRoot.Add(xElement);
                        }
                        else if (slugREX.IsMatch(newRequest))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.PostView.ToString());

                            xElement = new XElement("Year", slugREX.Replace(newRequest, "$2"));
                            xRoot.Add(xElement);

                            xElement = new XElement("Month", slugREX.Replace(newRequest, "$3"));
                            xRoot.Add(xElement);

                            xElement = new XElement("Day", slugREX.Replace(newRequest, "$4"));
                            xRoot.Add(xElement);

                            data = Parse(slugREX.Replace(newRequest, "$5"), true, settings);
                            xElement = new XElement("Slug", data.path);
                            xRoot.Add(xElement);

                            _postPath = "/" + slugREX.Replace(newRequest, "$2") + "/" + slugREX.Replace(newRequest, "$3") + "/" + slugREX.Replace(newRequest, "$4") + "/" + slugREX.Replace(newRequest, data.path);

                            xElement = new XElement("PostPath", _postPath);
                            xRoot.Add(xElement);
                        }
                        else if (dayREX.IsMatch(newRequest))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.DayView.ToString());

                            xElement = new XElement("Year", dayREX.Replace(newRequest, "$2"));
                            xRoot.Add(xElement);

                            xElement = new XElement("Month", dayREX.Replace(newRequest, "$3"));
                            xRoot.Add(xElement);

                            data = Parse(dayREX.Replace(newRequest, "$4"), true, settings);
                            xElement = new XElement("Day", data.path);
                            xRoot.Add(xElement);
                        }
                        else if (monthREX.IsMatch(newRequest))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.MonthView.ToString());

                            xElement = new XElement("Year", monthREX.Replace(newRequest, "$2"));
                            xRoot.Add(xElement);

                            data = Parse(monthREX.Replace(newRequest, "$3"), true, settings);
                            xElement = new XElement("Month", data.path);
                            xRoot.Add(xElement);
                        }
                        else if (yearREX.IsMatch(newRequest))
                        {
                            doc.Element("params").Element("RequestType").SetValue(RequestType.YearView.ToString());

                            data = Parse(yearREX.Replace(newRequest, "$2"), true, settings);
                            xElement = new XElement("Year", data.path);
                            xRoot.Add(xElement);
                        }
                    }
                }

                XElement xSettings = new XElement("Settings");
                XElement xSetting;
                foreach (string setting in settings.Keys)
                {
                    xSetting = new XElement(setting, settings[setting]);
                    xSettings.Add(xSetting);
                }
                xRoot.Add(xSettings);

                // Set Blog Details
                string tabPath = bnn.GetTabPath(portalID, tabID, moduleID);

                // Add Tab ID for non-SEO'd requests
                if (!settings.ContainsKey("FriendlierUrls") || !Convert.ToBoolean(settings["FriendlierUrls"]))
                    tabPath += "//tabid//" + tabID.ToString();

                XElement xBlog = new XElement("Blog",
                    new XElement("BlogDetails",
                        new XElement("PortalID", portalID.ToString()),
                        new XElement("ModuleID", moduleID.ToString()),
                        new XElement("TabID", tabID.ToString()),
                        new XElement("TabPath", tabPath),
                        new XElement("RelativeURL", GetPathExtension(doc, tabPath.Replace("//", "/"))),
                        new XElement("AbsoluteURL", (context.Request.IsSecureConnection ? "https://" : "http://") + context.Request.Url.Host + GetPathExtension(doc, tabPath.Replace("//", "/")))));
                xRoot.Add(xBlog);

                // Set Post Details
                if (doc.Element("params").Element("RequestType").Value.Equals(RequestType.PostView.ToString()))
                {
                    PostInfo post = null;

                    if (!string.IsNullOrEmpty(_postPath))
                        post = bnn.GetPostByPostPath(portalID, moduleID, _postPath);
                    else if (_postID != Guid.Empty)
                        post = bnn.GetPostByPostID(portalID, moduleID, _postID);

                    if (post != null)
                    {
                        XElement xPost = new XElement("Post",
                            new XElement("PostDetails",
                                new XElement("PostID", post.PostID.ToString()),
                                new XElement("Title", post.PostTitle),
                                new XElement("Slug", post.Slug),
                                new XElement("Content", post.Content),
                                new XElement("Excerpt", post.Excerpt),
                                new XElement("AllowComments", post.AllowComments.ToString()),
                                new XElement("Status", post.Status.ToString()),
                                new XElement("PublishedDate", post.PublishedDate.ToString()),
                                new XElement("PostPath", post.PostPath),
                                new XElement("Keywords", post.Keywords),
                                new XElement("Description", post.Description),
                                new XElement("RelativeURL", tabPath.Replace("//", "/") + GetPathExtension(doc, post.PostPath)),
                                new XElement("AbsoluteURL", (context.Request.IsSecureConnection ? "https://" : "http://") + context.Request.Url.Host + tabPath.Replace("//", "/") + GetPathExtension(doc, post.PostPath)),
                                new XElement("PermaLink", (context.Request.IsSecureConnection ? "https://" : "http://") + context.Request.Url.Host + GetPathExtension(doc, tabPath.Replace("//", "/")) + "?postID=" + post.PostID),
                                new XElement("TotalComments", post.TotalComments.ToString())),
                            new XElement("TabDetails",
                                new XElement("PortalID", post.PortalID.ToString()),
                                new XElement("TabID", post.TabID.ToString()),
                                new XElement("TabPath", tabPath),
                                new XElement("ModuleID", post.ModuleID.ToString())),
                            new XElement("AuthorDetails",
                                new XElement("AuthorID", post.AuthorID.ToString())));

                        xRoot.Add(xPost);
                    }
                }

                return doc;
            }
            catch
            {
                doc = new XDocument();
                xRoot = new XElement("params");
                doc.Add(xRoot);

                xRoot.Add(new XElement("RequestType", "undefined"));

                return doc;
            }
        }

        public static string GetSlug(string title)
        {
            // replace non letters, numbers and quotes 
            title = Regex.Replace(title, "['\"]", "");
            title = Regex.Replace(title, "[^A-Za-z0-9]", " ");

            // remove multiple spaces
            title = title.Replace("  ", " ").Trim();

            // substitude dashes for spaces
            title = title.Replace(" ", "-");

            return title;
        }

        public static string GetTabPath(int portalID, int tabID, int moduleID)
        {
            HttpContext context = HttpContext.Current;
            Components.BlogNetNukeController bnn = new Components.BlogNetNukeController();
            string path = bnn.GetTabPath(portalID, tabID, moduleID);

            return context.Request.Url.Host + path.Replace("//", "/") + "/";
        }

        public static string GetPathExtension(XDocument doc, string path)
        {
            if (doc.Element("params").Element("UsePageExtensions") != null)
            {
                if (Convert.ToBoolean(doc.Element("params").Element("UsePageExtensions").Value))
                    if ((doc.Element("params").Element("PageExtension") != null) && (!string.IsNullOrEmpty(doc.Element("params").Element("PageExtension").Value)))
                        path += doc.Element("params").Element("PageExtension").Value;
                    else
                        path += ".aspx";
            }
            else
                path += ".aspx";

            return path;
        }

        public static ParseData Parse(string request, BlogTab blog)
        {
            return Parse(request, true, blog);
        }

        public static ParseData Parse(string request, bool returnPath, BlogTab blog)
        {
            if (blog == null)
                throw new HttpException(404, "Not Found");

            Components.BlogNetNukeController bnn = new Components.BlogNetNukeController();
            Dictionary<string, string> settings = bnn.GetSettings(blog.PortalID, blog.ModuleID);

            return Parse(request, returnPath, settings);
        }

        public static ParseData Parse(string request, bool returnPath, Dictionary<string, string> settings)
        {
            ParseData data = new ParseData();

            if (request.StartsWith("/"))  // remove initial forward slash
                request = request.Substring(1);

            if (Convert.ToBoolean(settings["UsePageExtensions"]) && returnPath)
            {
                Regex extensionREX = new Regex("(.+)" + settings["PageExtension"] + "(.+)", RegexOptions.IgnoreCase);
                data.path = extensionREX.Replace(request, "$1");

                data.query = extensionREX.Replace(request, "$2");

                if (data.path.Equals(data.query))
                    data.query = string.Empty;

                if (data.path.EndsWith(settings["PageExtension"], StringComparison.InvariantCultureIgnoreCase))
                    data.path = data.path.Substring(0, data.path.Length - settings["PageExtension"].Length);

                if (data.query.Contains("?"))
                    data.query = data.query.Substring(data.query.IndexOf("?") + 1);

            }
            else
            {
                if (request.Contains("?"))
                    data.query = request.Substring(request.IndexOf("?") + 1);
            }

            if (!string.IsNullOrEmpty(data.query))
                data.query = "&" + data.query;

            return data;
        }

    }
}